package com.tungse.juc;

import java.util.concurrent.Semaphore;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.LockSupport;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @Author : Tungse
 * @Date: 2025/6/29 18:08
 * @Description:
 */
public class 交替打印输出 {
    private static final Object lock = new Object();
    private static int current = 1; // 当前应该执行的线程ID
    private static Thread threadA, threadB; // 两个线程
    private static volatile int index = 1; // 当前应该执行的线程ID

    public static void main(String[] args) {
        //synchronized 方式实现， 使用取余得到判断当前线程是否能够执行
        //test001();

        //使用volatile关键字实现
//        test002();

        //使用LockSupport实现
//        test003();

        //使用ReentrantLock实现
//        test004();

        //使用Semaphore 信号量 实现
        test005();

    }

    private static void test005() {
        Semaphore semaphore1 = new Semaphore(0);
        Semaphore semaphore2 = new Semaphore(0);
        new Thread(() -> {
            int idx = 0;
            while (idx < 100) {
                idx++;
                try {
                    semaphore1.acquire();
                    if (idx % 2 == 1) {
                        System.out.println(Thread.currentThread().getName() + "====" + idx);
                    }
                    semaphore2.release();
                } catch (InterruptedException ignore) {
                }
            }
        }, "threadA").start();;

        new Thread(() -> {
            int idx = 0;
            while (idx < 100) {
                idx++;
                try {
                    semaphore2.acquire();
                    if (idx % 2 == 0) {
                        System.out.println(Thread.currentThread().getName() + "====" + idx);
                    }
                    semaphore1.release();
                } catch (InterruptedException ignore) {
                }
            }
        }, "threadB").start();
        semaphore1.release();
    }

    private static void test004() {
        ReentrantLock reentrantLock = new ReentrantLock();
        Condition condition1 = reentrantLock.newCondition();
        Condition condition2 = reentrantLock.newCondition();
        new Thread(() -> {

            int idx = 0;
            while (idx < 100) {
                try {
                    reentrantLock.lock();
                    if (idx % 2 == 0) {
                        try {
                            condition1.await();
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                    }
                    idx++;
                    if(idx % 2 == 1) {
                        System.out.println(Thread.currentThread().getName() + "====" + idx);
                    }
                    condition2.signal();
                } finally {
                    reentrantLock.unlock();
                }
            }
        }, "t1").start();


        new Thread(() -> {
            int idx = 0;
            while (idx < 100) {
                try {
                    reentrantLock.lock();
                    if (idx % 2 == 1) {
                        try {
                            condition2.await();
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                    }
                    idx++;
                    if(idx % 2 == 0) {
                        System.out.println(Thread.currentThread().getName() + "====" + idx);
                    }
                    condition1.signal();
                } finally {
                    reentrantLock.unlock();
                }
            }

        }, "t2").start();

    }

    private static void test003() {

        threadA = new Thread(() -> {
            int idx = 0;
            while (idx < 100) {
                idx++;
                if (idx % 2 == 1) {
                    System.out.println(Thread.currentThread().getName() + "====" + idx);
                    LockSupport.unpark(threadB); // 唤醒t1线程
                } else {
                    LockSupport.park(); // 阻塞当前线程
                }
            }
            LockSupport.unpark(threadB);
        }, "threadA");

        threadB = new Thread(() -> {
            int idx = 0;
            while (idx < 100) {
                idx++;
                if (idx % 2 == 0) {
                    System.out.println(Thread.currentThread().getName() + "====" + idx);
                    LockSupport.unpark(threadA); // 唤醒t1线程
                } else {
                    LockSupport.park(); // 阻塞当前线程
                }
            }
            LockSupport.unpark(threadA);
        }, "threadB");
        threadA.start();
        threadB.start();
    }

    private static void test002() {
        new Thread(() -> {
            while (index < 100) {
                if (index % 2 == 0) {
                    System.out.println(Thread.currentThread().getName() + "====" + index);
                    index++;
                }
            }
        }, "t0").start();
        new Thread(() -> {
            while (index < 100) {
                if (index % 2 == 1) {
                    System.out.println(Thread.currentThread().getName() + "====" + index);
                    index++;
                }
            }
        }, "t1").start();
    }

    private static void test001() {
        int threadCount = 3; // 线程数量

        for (int i = 1; i <= threadCount; i++) {
            final int threadId = i;
            new Thread(() -> {
                for (int j = 0; j < 5; j++) { // 每个线程执行5次
                    synchronized (lock) {
                        // 不是当前线程的轮次就等待
                        while (threadId != current) {
                            try {
                                lock.wait();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }

                        // 执行线程任务
                        System.out.println("Thread-" + threadId + " 执行第" + (j + 1) + "次");

                        // 更新下一个执行的线程ID
                        current = (current % threadCount) + 1;

                        // 唤醒所有等待线程
                        lock.notifyAll();
                    }
                }
            }).start();
        }
    }
}
